#include <iostream>
#include <fstream>
#include <iomanip>

#include <signal.h>
#include <sys/types.h>
#include <fcntl.h>

#include "IOError.h"
#include "DigitalIO_DL636F.h"
#include "Counter_DL636G1.h"
#include "QDC_V792.h"
#include "EventStruct.h"
#include "timemeasure.h"

char *devfn="/tmp/sis1100_00remote";
bool quit = false;

//use channels 0 to 11
const static u_int32_t USED_CHANNELS  = 0xfff;
const static u_int32_t USED_THRESHOLD = 0x000;

const static u_int32_t MAX_EVENTS = 32;

void sigint_handler(int sig);

int main(int argc,char *argv[])
{
		const static u_int32_t BUFSIZE = 100000;
		EventStruct ev[BUFSIZE]; //events
		u_int32_t   ec[BUFSIZE]; //stores event counters;
		u_int32_t   qdc_ptr=0, read_ptr=0, end_margin=BUFSIZE;
		u_int32_t   start,stop;
		u_int32_t   start_time,stop_time;
		
		
		//install handler for CTRL-C
		signal(SIGINT,sigint_handler);
		
		cerr << "test_QDC_V792" << endl << endl;
		
		int crate;
		if( !(crate=open(devfn, O_RDWR, 0)) )
		{
				cerr << "ERROR: could not open \"" << devfn << "\"" << endl;
				exit(1);
		}

		TM_INIT();
		
		cerr << "vme reset...";
		vmesysreset(crate);
		cerr << "ok" << endl;
	
		DigitalIO_DL636F   io(crate,0x9900);
		Counter_DL636G1  cnt1(crate,0x9920);
		QDC_V792          qdc(crate,0x25390000);
	
		cerr << "using qdc @0x" << hex << qdc.getAddress()
         << ", cnt1 @0x" << cnt1.getAddress()
				 << ", io @0x" << io.getAddress() << dec << endl << endl;

		u_int32_t rc=0,hc=0,delta=0;
		try {
				io.setOutputs(0);
				cnt1.reset();
				cerr << "resetting qdc: ";
		
				cerr << "SoftwareReset..."; qdc.SoftwareReset(); cerr << "ok";
				cerr << ", DefineChannelBehaviour...";
				qdc.DefineChannelBehaviour(USED_CHANNELS,	USED_THRESHOLD);
				cerr << "ok";
				cerr << ", CountOnlyValidEvents...";
				qdc.CountOnlyValidEvents(); cerr << "ok";
				cerr << ", SetFastClearWindow()...";
				qdc.SetFastClearWindow(0); cerr << "ok";
				cerr << ", ClearBit2Pattern()...";
				qdc.ClearBit2Pattern( QDC_V792::BITSET_2_OVER_RANGE_ENABLED |
															QDC_V792::BITSET_2_LOW_THRESHOLD_ENABLED); 
				cerr << "ok";
				
		cerr << "\n\nmeasuring, press CTRL-C to quit" << endl;
		
		io.setO2(1);
		TM_START();
		start=clock(); start_time=time(NULL);
		io.setO1(1);
		
		while(!quit) {
				
				hc=cnt1.getC();
				delta=hc-rc;

//				usleep(10);

/*
				if( !qdc.BufferEmpty() ) {
						ec[qdc_ptr] = qdc.ReadEventFast(&(ev[qdc_ptr]));
						
						rc      ++;
						qdc_ptr ++;						
						
						if(qdc_ptr >= BUFSIZE-MAX_EVENTS) {
								end_margin=qdc_ptr;
								qdc_ptr=0;
						}
						if(qdc_ptr == read_ptr) {
								cerr << "buffer full, exit. (should better write out now)"
										 << endl;
								quit=true;
						}
				}
*/

				if( qdc.BufferFull() ) {						
						ec[qdc_ptr] = qdc.ReadEvents(&(ev[qdc_ptr]),32);
						
						rc      += delta;
						qdc_ptr += delta;						
						
						if(qdc_ptr >= BUFSIZE-MAX_EVENTS) {
								end_margin=qdc_ptr;
								qdc_ptr=0;
						}
						if(qdc_ptr == read_ptr) {
								cerr << "buffer full, exit. (should better write out now)"
										 << endl;
								quit=true;
						}

				}

				
				//write out 32 events
				for(int i=0; i<32; i++) {
						if(read_ptr >= end_margin) read_ptr=0;
						if(read_ptr != qdc_ptr) {
								cout << ec[read_ptr];
				    
								u_int16_t *qdc = (u_int16_t*)(&ev[read_ptr]);
								for(u_int32_t i=0; i<12; i++)
										cout << " " << qdc[i];
								cout << endl;
				    
								read_ptr++;
						}
				}

				if((time(NULL) - start_time) > 20) quit=1;
		}    
    io.setO1(0);
		TM_STOP(); stop=clock(); stop_time=time(NULL);
		io.setO2(0);
		
		//TODO: read rest...
				
		} catch(IOError ioe) {
				TM_STOP();
				io.setOutputs(0);
				cerr << "catched IOError exception: " << ioe.getMsg() << endl 
						 << "param=0x" << hex << ioe.getParam() << dec << endl << endl;
		}
		
		cerr << "hc=" << hc
				 << " rc=" << rc
				 << " -> delta=" << delta
				 << endl;

		cerr << "got " << rc << " events" << endl
         << "alex: " << tm_secs << " seconds, rate = "
				 << rc/tm_secs << " Hz" << endl
		     << "clock(): " << (stop-start) << " seconds, "
				 << rc / ((stop - start) / CLOCKS_PER_SEC)
				 << " Hz" << endl
		     << "time(): " << (stop_time-start_time) << " seconds, "
				 << rc / ((stop_time - start_time))
				 << " Hz" << endl;

		cerr << "closing crate..."; close(crate); cerr << "ok\n\n";
		
		return 0;
}

void sigint_handler(int sig)
{
		cerr << "CTRL-C pressed" << endl;
		
		quit=true;
}
